package com.dkd.service.impl;

import cn.elegent.ac.ElegentAC;
import cn.elegent.actx.annotation.ACTransaction;
import cn.elegent.actx.context.ElegentACTXContext;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dkd.config.ACTXConfig;
import com.dkd.config.TopicConfig;
import com.dkd.config.constant.OrderStatus;
import com.dkd.config.constant.PayStatus;
import com.dkd.contract.VendoutContract;
import com.dkd.contract.VendoutData;
import com.dkd.dao.OrderDao;
import com.dkd.entity.OrderCollectEntity;
import com.dkd.entity.OrderEntity;
import com.dkd.entity.OrderSkuVo;
import com.dkd.entity.vo.BarCharCollect;
import com.dkd.exception.LogicException;
import com.dkd.feign.UserService;
import com.dkd.feign.VMService;
import com.dkd.service.OrderService;
import com.dkd.vo.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.Strings;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.metrics.ParsedSum;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
@RequiredArgsConstructor
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {
    @Autowired
    private VMService vmService;

    @Autowired
    private UserService userService;

    @Autowired
    private ElegentAC elegentAC;

    private final OrderDao orderDao;
    private final RestHighLevelClient esClient;

    @Override
    public OrderEntity getByOrderNo(String orderNo) {
        QueryWrapper<OrderEntity> qw = new QueryWrapper<>();
        qw.lambda().eq(OrderEntity::getOrderNo, orderNo);
        return this.getOne(qw);
    }

    @Override
    public OrderEntity createOrder(PayVO payVO, String platform) {
        if (!vmService.hasCapacity(payVO.getInnerCode(), Long.valueOf(payVO.getSkuId()))) {
            throw new LogicException("该商品已售空");
        }
        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setOpenId(payVO.getOpenId());//openId
        //封装平台名称
        orderEntity.setPayType(platform);
        orderEntity.setPayStatus(PayStatus.PAY_STATUS_NOPAY);//支付状态
        orderEntity.setStatus(OrderStatus.ORDER_STATUS_CREATE);//订单状态
        orderEntity.setOrderNo(payVO.getInnerCode() + System.nanoTime());//订单编号
        //根据售货机编号查询售货机信息 ,并复制给订单对象
        VmVO vm = vmService.getVMInfo(payVO.getInnerCode());
        BeanUtils.copyProperties(vm, orderEntity);
        orderEntity.setAddr(vm.getNodeAddr());

        //根据商品编号查询商品信息，并复制给订单对象
        SkuVO skuVo = vmService.getSku(payVO.getSkuId());
        BeanUtils.copyProperties(skuVo, orderEntity);
        orderEntity.setAmount(skuVo.getRealPrice());//价格
        //计算合作商账单分账金额
        PartnerVO partner = userService.getPartner(vm.getOwnerId());

        //如果订单的价格低于10分钱 则不统计分账
        if (skuVo.getRealPrice() < 10) {
            orderEntity.setBill(0);
        } else {
            // 高精度数据类型 : MYSQL数据库 Decimal类型 , Java : BigDecimal
            BigDecimal bg = new BigDecimal(skuVo.getRealPrice());
            int bill = bg.multiply(new BigDecimal(partner.getRatio())).divide(new BigDecimal(100), 0, RoundingMode.HALF_UP).intValue();
            orderEntity.setBill(bill);
        }
        this.save(orderEntity);
        return orderEntity;
    }

    @Override
    @ACTransaction(mainName = ACTXConfig.ORDER_VENDOUT, childName = ACTXConfig.ORDER_VENDOUT_PAY)
    public boolean vendout(String orderNo, Long skuId, String innerCode, Integer amount) {
        //封装协议中的数据
        var reqData = new VendoutData();
        reqData.setOrderNo(orderNo);
        reqData.setSkuId(skuId);
        reqData.setAmount(amount);
        //封装协议
        var contract = new VendoutContract();
        contract.setVendoutData(reqData);
        contract.setInnerCode(innerCode);
        //保存数据快照
        ElegentACTXContext.setSnapshot("vendoutContract", contract); //保存快照

        //向售货机微服务  发送出货请求
        return elegentAC.publish(TopicConfig.VMS_VENDOUT_TOPIC, contract);
    }

    @Override
    public List<Long> getByBId(Long businessId) {
        return orderDao.getByBId(businessId);
    }

    @Override
    public List<OrderSkuVo> getSupplyCount(String innerCode, Date start, Date end) {
        return orderDao.getSupplyCount(innerCode, start, end);
    }

    @Override
    public Long getAmount(Integer partnerId, String innerCode, LocalDate start, LocalDate end) {
        Long amount = orderDao.getAmount(partnerId, innerCode, start, end);
        if (amount==null){
            return 0L;
        }
        return  amount;

    }

    @Override
    public Long getCount(Integer partnerId, String innerCode, LocalDate start, LocalDate end) {
        List<OrderEntity> list = this.lambdaQuery().eq(partnerId != null, OrderEntity::getOwnerId, partnerId)
                .eq(!Strings.isNullOrEmpty(innerCode), OrderEntity::getInnerCode, innerCode)
                .between(OrderEntity::getCreateTime, start, end)
                .list();
        if (list==null){
            return 0L;
        }
        return Long.valueOf(list.size());
    }

    @Override
    public List<OrderSkuVo> getBusinessTop10Skus(Integer topValue, LocalDate start, LocalDate end) {
        if (topValue==null){
            topValue=10;
        }
        return orderDao.getBusinessTop10Skus(topValue,start,end);
    }


}
